'''
Created on Mar 31, 2011

@author: leo
'''

import urllib2, urllib
import urlparse
import uuid
import random, string
import mimetypes
import simplejson
import cStringIO as StringIO
from printjob import PrintJob

# url to google cloud print
GOOGLE_SCHEMA = 'https'
GOOGLE_DOMAIN = 'www.google.com'
GCP_FORMAT = 'cloudprint/%s'

def GcpUrl(path, query=''):
    if type(query)  is dict:
        query = urllib.urlencode(query)
    return urlparse.urlunparse((GOOGLE_SCHEMA, GOOGLE_DOMAIN, GCP_FORMAT % path, '', query, ''))

# exception when access denied 
class AuthorizationError(Exception):
    def __init__(self):
        pass

class GoogleCloudPrint():
    '''
    provide interfaces to fetch data from google cloud print
    '''
    
    SEARCH_PRINTER_ACTION = 'search'
    GET_PRINTER_INFO_ACTION = 'printer'
    SUBMIT_JOB_ACTION = 'submit'
    FETCH_PRINT_JOB_ACTION = 'fetch'

    def __init__(self, user):
        self.user = user

    @classmethod
    def do_url_fetch(cls, url, access_token, data=None, content_type=None):
        request = urllib2.Request(url)
        request.add_header('Authorization', '%s %s' % ('OAuth', access_token))
        if content_type:
            request.add_header('Content-Type', content_type)
        
        opener = urllib2.build_opener()
        try:
            rsp = opener.open(request, data)
            ct = rsp.info().getheader('Content-Type')
            data = rsp.read()
        
        except urllib2.HTTPError, he:
            if he.code == 401 or he.code == 403:
                raise AuthorizationError()
            else:
                raise he  # reraise it if the cause is unknown
        else:
            return ct, data
            

    def search_printers(self):
        url = GcpUrl(self.SEARCH_PRINTER_ACTION)
        ct, data = self.do_url_fetch(url, self.user.get_access_token())
        return data
        #js = simplejson.loads(data)
        #return js['success'] and js['printers'] or []
    
    def get_printer_info(self, printerid):
        url = GcpUrl(self.GET_PRINTER_INFO_ACTION, {'printerid':printerid})
        ct, data = self.do_url_fetch(url, self.user.get_access_token())
        return data
    
    def fetch_print_job(self, printerid):
        url = GcpUrl(self.FETCH_PRINT_JOB_ACTION, {'printerid':printerid})
        ct, data = self.do_url_fetch(url, self.user.get_access_token())
        js = simplejson.loads(data)
        jobs = []
        if js['success']:
            for p in js['jobs']:
                job = PrintJob(id=p['id'], 
                               printerid=p['printerid'], 
                               title=p['title'], 
                               contentType=p['contentType'],
                               fileUrl=p['fileUrl'], 
                               ticketUrl=p['ticketUrl'])
                jobs.append(job)
        return jobs

    def fetch_data(self, url):
        ct, data = self.do_url_fetch(url, self.user.get_access_token())
        return ct, data

    def submit_print_job(self, printerid, contentType, content, title=None, capabilities='{"capabilities":[]}'):
        if(title is None):
            title = str(uuid.uuid4())
        
        fields = {
                  'printerid': printerid,
                  'contentType': contentType,
                  'title': title,
                  'capabilities': capabilities,
                  }

        files = {}
        if(type(content) == tuple):
            files['content'] = content
        else:
            fields['content'] = content
            
        boundary, data = self.encode_multipart_form(fields, files)
        ct = 'multipart/form-data; boundary=%s' % boundary

        url = GcpUrl(self.SUBMIT_JOB_ACTION)
        ct, data = self.do_url_fetch(url, self.user.get_access_token(), data, ct)
        return data

    @classmethod
    def choose_boundary(cls):
        return ''.join((random.choice(string.ascii_letters + string.digits) for x in range(16)))
    
    @classmethod
    def encode_multipart_form(cls, vars, files):
        ''' files is a list of 2-tuple(filename, content) '''
        boundary = cls.choose_boundary()
        buffer = StringIO.StringIO()
        for(key, value) in vars.items():
            buffer.write('--%s\r\n' % boundary)
            buffer.write('Content-Disposition: form-data; name="%s"\r\n' % key)
            buffer.write('\r\n')
            buffer.write(value)
            buffer.write('\r\n')
        for(key, fd) in files.items():
            filename = fd[0]
            contenttype = mimetypes.guess_type(filename)[0] or 'application/octet-stream'
            buffer.write('--%s\r\n' % boundary)
            buffer.write('Content-Disposition: form-data; name="%s"; filename="%s"\r\n' % (key, filename))
            buffer.write('Content-Type: %s\r\n' % contenttype)
            buffer.write('\r\n')
            buffer.write(fd[1])
            buffer.write('\r\n')
        buffer.write('--%s--\r\n\r\n' % boundary)
        return boundary, buffer.getvalue()
